package com.lingyun.framework.aspect;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lingyun.common.annotation.DataJurisdiction;
import com.lingyun.common.corebase.BaseEntity;
import com.lingyun.common.exception.ServiceException;
import com.lingyun.common.pojo.LyRole;
import com.lingyun.common.pojo.LyUser;
import com.lingyun.common.utils.security.SecurityUtils;
import com.lingyun.common.vo.LoginUser;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 没事别学JAVA
 * 2021/12/28 2:59
 */

@Aspect
@Component
public class DataJurisdictionAspect {

    /**
     * 全部数据权限
     */
    public static final String DATA_SCOPE_ALL = "1";

    /**
     * 自定数据权限
     */
    public static final String DATA_SCOPE_CUSTOM = "2";

    /**
     * 角色数据权限
     */
    public static final String DATA_SCOPE_ROLE = "3";

    /**
     * 仅本人数据权限
     */
    public static final String DATA_SCOPE_SELF = "4";

    /**
     * 数据权限过滤关键字
     */
    public static final String DATA_SCOPE = "dataScope";


//    /**
//     * 业务逻辑开始之前执行  方式一 自定义注解要传值的
//     * @param joinPoint 切点
//     */
//    @Before("@annotation(dataJurisdiction)")    ////@annotation声明以注解的方式来定义切点
//    public void beforeMethod(JoinPoint joinPoint,DataJurisdiction dataJurisdiction){
//
//    }


    /**
     * 业务逻辑开始之前执行 方式二 自定义注解不传值的
     *
     * @param joinPoint 切点
     * @annotation 声明以注解的方式来定义切点
     */
    @Before("@annotation(com.lingyun.common.annotation.DataJurisdiction)")    //
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("数据权限业务逻辑开始执行之前执行.......");
        clearDataScope(joinPoint);
        handleDataScope(joinPoint);
    }

    /**
     * 拼接权限sql前先清空params.dataScope参数防止注入
     *
     * @param joinPoint 切点
     */
    private void clearDataScope(final JoinPoint joinPoint) {
        Object params = joinPoint.getArgs()[0]; // 是在方法括号中的对象
        // 1、isNotNull判断是否为null（true：非空 false：空）  2、instanceof 判断前面的对象是否属于后面的类，或者属于其子类
        if (ObjectUtil.isNotNull(params) && params instanceof BaseEntity) {
            BaseEntity baseEntity = (BaseEntity) params;
            baseEntity.getParams().put(DATA_SCOPE, "");
        }
    }

    /**
     * 数据处理
     *
     * @param joinPoint 切点
     */
    public void handleDataScope(final JoinPoint joinPoint) {
        LoginUser loginUser = SecurityUtils.getLoginUser();  // 获取当前用户信息
        if (ObjectUtil.isNotNull(loginUser)) {
            LyUser lyUser = loginUser.getLyUser();
            //isNotNull判断是否为null（true：非空 false：空）     如果是超级管理员，则不过滤数据
            if (ObjectUtil.isNotNull(lyUser) && !loginUser.getRoles().contains("admin")) {
                dataScopeFilter(joinPoint, lyUser);
            }
        }
    }

    /**
     * String template = "{}爱{}，就像老鼠爱大米";
     * String str = StrUtil.format(template, "我", "你"); //str -> 我爱你，就像老鼠爱大米
     * 数据范围过滤
     *
     * @param joinPoint 切点
     * @param lyUser    用户
     */
    public static void dataScopeFilter(JoinPoint joinPoint, LyUser lyUser) {
        StringBuilder sqlString = new StringBuilder();
        List<String> conditions = new ArrayList<String>();
        for (LyRole role : lyUser.getLyRoles()) {
            String dataScope = role.getDataScope();
            if (conditions.contains(dataScope)) {
                //continue 语句会终止本次循环，循环体中 continue 之后的语句将不再执行，接着进行下次循环
                continue;
            }
            if (DATA_SCOPE_ALL.equals(dataScope)) { // 全部数据权限
                sqlString = new StringBuilder();
            } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { // 自定义数据权限
                sqlString.append(StrUtil.format(" WHERE ly_role.role_id = {} ", role.getRoleId()));
            } else if (DATA_SCOPE_ROLE.equals(dataScope)) { // 角色数据权限
                sqlString.append(StrUtil.format(" WHERE ly_user.user_id = {} ", lyUser.getUserId()));
            } else if (DATA_SCOPE_SELF.equals(dataScope)) { // 本人数据权限
                sqlString.append(StrUtil.format(" or ly_user.user_id = {} ", lyUser.getUserId()));
            }
            conditions.add(dataScope);
        }
        if (StrUtil.isNotEmpty(sqlString.toString())) {
            Object params = joinPoint.getArgs()[0];
            if (ObjectUtil.isNotNull(params) && params instanceof BaseEntity) {
                BaseEntity baseEntity = (BaseEntity) params;
                baseEntity.getParams().put(DATA_SCOPE, " and ( " + sqlString.substring(4) + ")");
            }
        }
    }


    /**
     * 业务逻辑结束时执行
     *
     * @param dataJurisdiction
     */
    @After("@annotation(dataJurisdiction)")
    public void afterMethod(DataJurisdiction dataJurisdiction) {
        System.out.println("数据权限业务逻辑结束时执行，无论异常与否都执行.......");
    }


}
